home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
C/C++ Users Group Library 1996 July
/
C-C++ Users Group Library July 1996.iso
/
vol_300
/
355_02
/
slk2.exe
/
SPP
/
DIR.C
< prev
next >
Wrap
C/C++ Source or Header
|
1991-06-09
|
22KB
|
1,093 lines
/*
New Sherlock Preprocessor -- directives
source: dir.c
started: October 7, 1985
version: July 20, 1988; June 9, 1991
June 9, 1991: bug fix to pp_elif
February 10, 1989: bug fix in pp_include.
February 16, 1989: periods removed from error messages.
March 3, 1989: fix bug in do_pp.
External routines defined in this file: do_pp
PUBLIC DOMAIN SOFTWARE
Sherlock, including the SPP, SDEL and SDIF programs, was placed in
the public domain on June 15, 1991, by its author,
Edward K. Ream
166 North Prospect Ave.
Madison, WI 53705.
(608) 257-0802
Sherlock may be used for any commercial or non-commercial purpose.
DISCLAIMER OF WARRANTIES
Edward K. Ream (Ream) specifically disclaims all warranties,
expressed or implied, with respect to this computer software,
including but not limited to implied warranties of merchantability
and fitness for a particular purpose. In no event shall Ream be
liable for any loss of profit or any commercial damage, including
but not limited to special, incidental consequential or other damages.
*/
#include "spp.h"
#define TRACE_LINE(name) TRACEP(name, printf("line %d\n", t_line))
static long eval (void);
static long eval1 (void);
static bool gt_prec (en_tokens, en_tokens);
static bool isfnch (int, en_tokens);
static void pp_elif (void);
static void pp_else (void);
static void pp_endif (void);
static void pp_enum (void);
static void pp_error (void);
static void pp_if (void);
static void pp_ifdef (bool);
static void pp_incl (void);
static void pp_line (void);
static void pp_undef (void);
static int prec (int);
static void push_op (en_tokens);
static en_tokens pop_op (void);
static void push_val (long);
static long pop_val (void);
static void skip_lines (void);
typedef enum {
IF_BEGIN = 0,
IF_ELSE = 1,
IF_ELIF = 2
} if_state;
#define MAX_IF 50
static if_state if_stack [ MAX_IF ];
static int if_level = 0;
/*
Do one preprocessor directive.
*/
#define EQL(string) str_eq(t_symbol+1,string+1)
void
do_pp()
{
TICK("do_pp");
syshflush();
skip_ws(FALSE);
/* Get the directive into t_symbol[]. */
if (!isalpha(ch)) {
goto not_alpha;
}
t_id(t_symbol, MAX_SYMBOL);
/* 3/3/89 */
skip_ws(FALSE);
/* Skip simple white space after the directive. */
/* -----
while (ch == ' ' || ch == '\t') {
sysnext();
}
----- */
switch(t_symbol [0]) {
case 'd':
if (t_length == 6 && EQL("define")) {
pp_def();
return;
}
goto not_pp;
case 'e':
if (t_length == 4) {
if (EQL("else")) {
pp_else();
return;
}
else if (EQL("elif")) {
pp_elif();
return;
}
}
#ifdef HAS_PP_ENUM
else if (t_length == 4 && EQL("enum")) {
pp_enum();
return;
}
#endif
else if (t_length == 5 && EQL("endif")) {
pp_endif();
return;
}
else if (t_length == 5 && EQL("error")) {
pp_error();
return;
}
goto not_pp;
case 'i':
switch(t_length) {
case 2: if (EQL("if")) {
pp_if();
return;
}
goto not_pp;
case 5: if (EQL("ifdef")) {
pp_ifdef(TRUE);
return;
}
goto not_pp;
case 6: if (EQL("ifndef")) {
pp_ifdef(FALSE);
return;
}
goto not_pp;
case 7: if (EQL("include")) {
pp_incl();
return;
}
goto not_pp;
}
goto not_pp;
case 'l':
if (t_length == 4 && EQL("line")) {
pp_line();
return;
}
goto not_pp;
case 'p':
if (t_length == 6 && EQL("pragma")) {
/* Do NOTHING!! */
skip_pp();
return;
}
goto not_pp;
case 'u':
if (t_length == 5 && EQL("undef")) {
pp_undef();
return;
}
goto not_pp;
default:
goto not_pp;
}
not_alpha:
/*
Be more permissive than the new C standard.
Just skip the rest of the line.
*/
skip_pp();
return;
not_pp:
err2(t_symbol, " is not a valid preprocessor directive");
skip_pp();
}
#undef EQL
/*
Handle the #error directive.
Instead of producing a diagnostic message, just copy it.
*/
static void
pp_error()
{
skip_pp();
}
/*
Evaluate a constant expression to either true or false.
A constant expression consists of:
1. integer constants or character constants
2. the unary - + and ~ operators
3. the binary + - * / & | ^ << >> == != < > <= >= oprators
4. the ternary ? : operator
5. the ( and ) groupers.
Identifiers are expanded if they are defined, otherwise they
are taken to have a value of zero. All arithmetic is integer and
ints are expanded to long.
*/
#define MAX_EVAL_VAL 100
#define MAX_EVAL_OP 50
static long val_stack[MAX_EVAL_VAL];
static int val_ptr = 0;
static en_tokens op_stack[MAX_EVAL_OP];
static int op_ptr = 0;
static long result;
static bool paren_seen;
static bool error_seen;
static long
eval()
{
TRACETOK("eval");
error_seen = FALSE;
con_flag = TRUE;
get_token();
result = eval1();
con_flag = FALSE;
RETURN_LONG("eval", result);
}
static char * junk;
static int junki;
static long
eval1()
{
register en_tokens op, op2;
register long val1, val2, val3;
int op_1ptr;
TRACETOK("eval1");
op_1ptr = op_ptr;
/* State S1: unary +, unary -, !, ~, constant or id is expected here. */
s1:
TRACEPN("v_eval1", printf("at state 1\n"));
while (is(PLUS_TOK) || is(MINUS_TOK) || is(TILDE_TOK) || is(NOT_TOK)) {
if (is(PLUS_TOK)) {
push_op(UPLUS_TOK);
}
else if (is(MINUS_TOK)) {
push_op(UMINUS_TOK);
}
else if (is(NOT_TOK)) {
push_op(NOT_TOK);
}
else {
push_op(TILDE_TOK);
}
get_token();
}
/* We expect a constant or identifier here. */
if (is(INT_TOK) || is(LONG_TOK) || is(CHAR_TOK)) {
push_val((long) t_value);
get_token();
}
else if (is(ID_TOK)) {
/* Special case defined id and defined(id). */
if (str_eq(t_symbol, "defined")) {
/* Do not macro expand an id here! */
get_xtoken();
if (!is(ID_TOK) && !is(LPAREN_TOK)) {
error("Id or '(' expected after 'defined'");
goto bad_expr;
}
paren_seen = is(LPAREN_TOK);
if (paren_seen) {
get_xtoken();
if (!is(ID_TOK)) {
error("Id expected after '('");
goto bad_expr;
}
}
if(mst_lookup(t_symbol, &junk, &junki)) {
push_val(1L);
}
else {
push_val(0L);
}
get_token();
if (paren_seen) {
if (is(RPAREN_TOK)) {
get_token();
}
else {
error("')' expected");
goto bad_expr;
}
}
}
else {
/* The identifier must be undefined, so it gets 0. */
push_val(0L);
get_token();
}
}
else if (is(LPAREN_TOK)) {
get_token();
/* Evaluate the expression recursively. */
result = eval1();
if (is(RPAREN_TOK)) {
get_token();
push_val(result);
}
else {
error("')' expected");
goto bad_expr;
}
}
else {
error("Integer constant or parenthesized expression expected");
goto bad_expr;
}
/* Perform all unary ops and enter state S2. */
TRACEPN("v_eval1", printf("at state 1A\n"));
while (op_ptr > op_1ptr) {
switch (op = pop_op()) {
case UPLUS_TOK: break;
case UMINUS_TOK: push_val(-pop_val()); break;
case NOT_TOK: push_val((long)(!pop_val())); break;
case TILDE_TOK: push_val(~pop_val()); break;
default: push_op(op); goto s2;
}
}
/* State S2: binary op or end_of_expression expected here. */
s2:
TRACEPN("v_eval1", printf("at state 2\n"));
/*
Perform binary operators until the operator stack is
empty or until token operator has a higher precedence
than the operator on the top of the operator stack.
*/
while (op_ptr > op_1ptr && gt_prec(op_stack[op_ptr - 1], token)) {
val2 = pop_val();
val1 = pop_val();
op = pop_op();
switch (op) {
case PLUS_TOK: push_val(val1 + val2); break;
case MINUS_TOK: push_val(val1 - val2); break;
case STAR_TOK: push_val(val1 * val2); break;
case DIV_TOK: push_val((long)(val2?(val1/val2):0));
break;
case MOD_TOK: push_val(val1 % val2); break;
case AND_TOK: push_val(val1 &